/* Copyright@Han MA
 * 
 * 03/06/2006 
 * 
 * 
 */


using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace MyEditor
{

    class Watershed
    {
        int k;
        const int INIT = -1;
        const int MASK = -2;
        const int WSHED = 0;
        MyPixel FICTITIOUS = new MyPixel(-1, -1, -1000);
        int curlab;
        int curdist;
        Bitmap pic,pic2;
        FifoQue que = new FifoQue();
        List<List<MyPixel>> HightSortedList = new List<List<MyPixel>>();
        int[,] lab;
        int[,] dist;
        bool done = false;

        public Watershed(Bitmap pic,int k,Bitmap pic2)
        {
            this.pic2 = pic2;
            this.k = k;
            for (int i = 0; i < k; i++)
            {
                HightSortedList.Add(new List<MyPixel>());
            }
            this.pic =new Bitmap(pic);
           
           
            lab = new int[pic.Width, pic.Height];
            dist = new int[pic.Width, pic.Height];


            unsafe
            {
                BitmapData data = pic.LockBits
                    (new Rectangle(0, 0, pic.Width, pic.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                byte* imgPtr = (byte*)(data.Scan0);

                for (int i = 0; i < data.Height; i++)
                {
                    for (int j = 0; j < data.Width; j++)
                    {

                        int hight = imgPtr[0];
                        HightSortedList[hight].Add(new MyPixel(j, i, hight));
                        lab[j, i] = INIT;
                        dist[j, i] = 0;
                        imgPtr += 3;
                    }
                    imgPtr += data.Stride - data.Width * 3;
                }
                pic.UnlockBits(data);
            }
            this.curlab = 0;
        }

        public int getLabCount()
        {
            if (done)
                return curlab;
            else
                return -1;
        }

        public void DoWaterShed()
        {
            done = true;

            for (int h = 0; h < k; h++)
            {
                //foreach (MyPixel p in HightSortedList[h])
                for (int i = 0; i < HightSortedList[h].Count; i++)
                {
                    lab[HightSortedList[h][i].x, HightSortedList[h][i].y] = MASK;
                    //foreach (MyPixel nighb in Nighbour(p))
                    List<MyPixel> nighb = new List<MyPixel>();
                    nighb = Nighbour(HightSortedList[h][i]);
                    for (int n = 0; n < nighb.Count; n++)
                    {
                        if (lab[nighb[n].x, nighb[n].y] > 0 || lab[nighb[n].x, nighb[n].y] == WSHED)
                        {
                            dist[HightSortedList[h][i].x, HightSortedList[h][i].y] = 1;
                            que.add(HightSortedList[h][i]);
                            break;

                        }

                    }
                }

                curdist = 1;
                que.add(FICTITIOUS);
                while (true)
                {
                    MyPixel p = new MyPixel();
                    p = que.remove();
                    if ((p.x == -1) && (p.y == -1))
                    {
                        if (que.IsEmpty())
                            break;
                        else
                        {
                            que.add(FICTITIOUS);
                            curdist++;
                            p = que.remove();
                        }
                    }
                    //foreach (MyPixel q in Nighbour(p))
                    List<MyPixel> nighb = new List<MyPixel>();
                    nighb = Nighbour(p);
                    for (int n = 0; n < nighb.Count; n++)
                    {
                        if ((dist[nighb[n].x, nighb[n].y] < curdist) && ((lab[nighb[n].x, nighb[n].y] > 0) || (lab[nighb[n].x, nighb[n].y] == WSHED)))
                        {
                            if (lab[nighb[n].x, nighb[n].y] > 0)
                            {
                                if (lab[p.x, p.y] == MASK || lab[p.x, p.y] == WSHED)
                                    lab[p.x, p.y] = lab[nighb[n].x, nighb[n].y];
                                else
                                {
                                    if (lab[p.x, p.y] != lab[nighb[n].x, nighb[n].y])
                                        lab[p.x, p.y] = WSHED;
                                }

                            }
                            else
                            {
                                if (lab[p.x, p.y] == MASK)
                                    lab[p.x, p.y] = WSHED;
                            }
                        }
                        else
                        {
                            if ((lab[nighb[n].x, nighb[n].y] == MASK) && (dist[nighb[n].x, nighb[n].y] == 0))
                            {
                                dist[nighb[n].x, nighb[n].y] = curdist + 1;
                                que.add(nighb[n]);
                            }
                        }

                    }
                }
                foreach (MyPixel p in HightSortedList[h])
                {
                    dist[p.x, p.y] = 0;
                    if (lab[p.x, p.y] == MASK)
                    {
                        curlab++;
                        que.add(p);
                        lab[p.x, p.y] = curlab;
                    }
                    while (!que.IsEmpty())
                    {
                        MyPixel q = new MyPixel();
                        q = que.remove();
                        foreach (MyPixel r in Nighbour(q))
                        {
                            if (lab[r.x, r.y] == MASK)
                            {
                                que.add(r);
                                lab[r.x, r.y] = curlab;
                            }
                        }
                    }
                }
            }
            edgefind();

        }
        void edgefind()
        {
            for (int i = 1; i < pic.Width-1; i++)
                for (int j = 1; j < pic.Height-1; j++)
                {
                    if (lab[i, j] == 0)
                    {
                        j = j + 2;
                        if (j >= pic.Height - 1)
                            continue;
                    }
                    if (lab[i,j-1]!=lab[i,j+1])
                        if ((lab[i,j-1]!=0)&&(lab[i,j+1]!=0))
                        lab[i,j]=0;
                }
            
                for (int j = 1; j < pic.Height - 1; j++)
                    for (int i = 1; i < pic.Width - 1; i++)
                {
                    if (lab[i, j] == 0)
                    {
                        i = i + 2;
                        if (i >= pic.Width - 1)
                            continue;
                    }
                    if (lab[i-1, j ] != lab[i+1, j])
                        if ((lab[i-1, j ] != 0) && (lab[i-1, j] != 0))
                            lab[i, j] = 0;
                }
        }

        public List<MyPixel> Nighbour(MyPixel p) 
        {
            List<MyPixel> temp = new List<MyPixel>();
            if ((p.x - 1) >= 0)

                temp.Add(new MyPixel((p.x - 1), p.y));


            if ((p.y - 1) >= 0)

                temp.Add(new MyPixel(p.x, (p.y - 1)));

            if ((p.x + 1) < pic.Width)

                temp.Add(new MyPixel((p.x + 1), p.y));

            if ((p.y + 1) < pic.Height)

                temp.Add(new MyPixel(p.x, (p.y + 1)));

            if ((p.x - 1) >= 0 && (p.y - 1) >= 0)

                temp.Add(new MyPixel(p.x - 1, p.y - 1));

            if ((p.x - 1) >= 0 && (p.y + 1) < pic.Height)

                temp.Add(new MyPixel(p.x - 1, p.y + 1));

            if ((p.x + 1) < pic.Width && (p.y - 1) >= 0)
                temp.Add(new MyPixel(p.x + 1, p.y - 1));


            if ((p.x + 1) < pic.Width && (p.y + 1) < pic.Height)
                temp.Add(new MyPixel(p.x + 1, p.y + 1));

            return temp;
        }

        public int[,] segMap()
        {
            return lab;
        }

        public Bitmap GetSegPic()
        {

            /*
             * List<MyPixel> WshdPixels = new List<MyPixel>();
            for (int h = 0; h < 256; h++)
                foreach (MyPixel p in HightSortedList[h])
                {
                    if (lab[p.x,p.y]== WSHED)
                        WshdPixels.Add(p);
                }*/

           /* unsafe
            {

                BitmapData data = pic2.LockBits
                   (new Rectangle(0, 0, pic.Width, pic.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                byte* imgPtr = (byte*)(data.Scan0);
                for (int i = 0; i < data.Height; i++)
                {
                    for (int j = 0; j < data.Width; j++)
                    {
                        Random ran;
                        int r1;r2;r3;
                        r1 = ran.Next(256);
                        r2 = ran.Next(256);
                        r3= ran.Next(256);

                        imgPtr[0]=ran.Next(

                        /* if (this.lab[j, i]<3000)
                         {
                             imgPtr[0] = 255;
                             imgPtr[1] = 0;
                             imgPtr[2] = 0;
                         }
                         else
                         {
                        //if ((this.lab[j, i]) == 1)
                        //{

                           // imgPtr[0] = 255;
                            //imgPtr[1] = 0;
                            //imgPtr[2] = 0;
                        //}
                        //else if ((this.lab[j, i] % 3) == 1)
                        //{
                            //imgPtr[0] = 0;
                           // imgPtr[1] = 255;
                            //imgPtr[2] = 0;

                       // }
                        //else if ((this.lab[j, i] % 3) == 2)
                        //{
                         //   imgPtr[0] = 0;
                        //    imgPtr[1] = 0;
                        //    imgPtr[2] = 255;

                       // }
                        imgPtr += 3;
                    }

                    imgPtr += data.Stride - data.Width * 3;
                }
                


                pic2.UnlockBits(data);
            }*/
            int r, g, b;

            for (int i = 0; i < pic.Height; i++)
            {
                for (int j = 0; j < pic.Width; j++)
                {
                    if (lab[j, i] == 0)
                    {
                        //r = g = b = 0;
                        pic2.SetPixel(j, i, Color.Black);
                    }
                    //else
                    {


                        /*//r = (lab[j, i] * 1000) % 256;
                        //g = (lab[j, i] * lab[j, i] * 100) % 256;
                        //b = 0;// (lab[j, i] * lab[j, i] * lab[j, i] * 100) % 256;
                        //if (r < 0)
                            r = -r;
                        if (g < 0)
                            g = -g;
                        if (b < 0)
                            b = -b;
                        //r = g = b = 255;*/
                    }

                    //pic.SetPixel(j, i, Color.FromArgb(r,g,b));
                }
            }
            return pic2;
        }




    }

}




